
#include "unity.h"
#include "parse2_Rxpacket.h"
#include "mock_eth2_commom.h"


// Include any other necessary mocks or headers

void setUp(void)
{
    // Set up before each test
}

void tearDown(void)
{
    // Clean up after each test
}

void test_parse_Rxpacket_Should_Return_ETH_FRAME_PROTOCOL_ERR_When_Not_IPv6(void)
{
    // Arrange
    Eth_Service eth_service = {0};
    u8 rx_frame[1500] = {0};
    struct eth_header* ethhdr = (struct eth_header*)rx_frame;
    ethhdr->ether_type = 0x0800; // Not IPv6 (this is IPv4)
    
    // eth_service.RxFrame = rx_frame;

    // Instead of assigning the pointer, copy the data into the array
    memcpy(eth_service.RxFrame, rx_frame, sizeof(rx_frame));
   

    u8* rcvbuf = NULL;
    u32 size = 0;
    
    // Act
    u32 result = parse_Rxpacket(&eth_service, rcvbuf, &size);
    
    // Assert
    TEST_ASSERT_EQUAL(ETH_FRAME_PROTOCOL_ERR, result);
    TEST_ASSERT_EQUAL(0, size);
    TEST_ASSERT_NULL(rcvbuf);
}

void test_parse_Rxpacket_Should_Return_ETH_FRAME_ICMPV6_When_ICMPv6_Packet(void)
{
    // Arrange
    Eth_Service eth_service = {0};
    u8 rx_frame[1500] = {0};
    u8 icmpv6_frame[1500] = {0};
    
    // Setup RxFrame as ICMPv6 packet
    struct eth_header* ethhdr = (struct eth_header*)rx_frame;
    ethhdr->ether_type = 0xDD86; // IPv6 in big endian
    
    struct ipv6_header* ip6hdr = (struct ipv6_header*)(rx_frame + IPV6_HEADER_LOC);
    ip6hdr->next_header = ICMPV6_PROTOCOL;
    
    // Fill source MAC and IP for response
    memcpy(ethhdr->src_mac, "\x00\x11\x22\x33\x44\x55", 6);
    memcpy(ip6hdr->src_ipaddr, "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10", 16);
    
    struct icmpv6_msg* icmp6_rx = (struct icmpv6_msg*)(rx_frame + ICMP_HEADER_LOC);
    icmp6_rx->identifier = 0x1234;
    icmp6_rx->sequence = 0x5678;
    
    // Copy data into arrays instead of assigning pointers
    memcpy(eth_service.RxFrame, rx_frame, sizeof(rx_frame));
    memcpy(eth_service.ICMPv6Frame, icmpv6_frame, sizeof(icmpv6_frame));
   
    
    u8* rcvbuf = NULL;
    u32 size = 0;
    
    // Expect the transLayer_checksum to be called and return a value
    // You might need to mock this function depending on your testing strategy
    // Mock the functions that will be called
    transLayer_checksum_ExpectAndReturn(eth_service.ICMPv6Frame, 0x1234);
    eth_FifoTransData_ExpectAndReturn(&eth_service, eth_service.ICMPv6Frame, sizeof(struct eth_icmpv6_frame), XST_SUCCESS);
    Xil_Htons_IgnoreAndReturn(0x3412);

    // Act
    u32 result = parse_Rxpacket(&eth_service, rcvbuf, &size);
    
    // Assert
    TEST_ASSERT_EQUAL(ETH_FRAME_ICMPV6, result);
    // Add more specific assertions about the constructed ICMPv6 response packet
}

void test_parse_Rxpacket_Should_Return_ETH_FRAME_PORT_ERR_When_UDP_Port_Too_Low(void)
{
    // Arrange
    Eth_Service eth_service = {0};
    u8 rx_frame[1500] = {0};
    
    struct eth_header* ethhdr = (struct eth_header*)rx_frame;
    ethhdr->ether_type = 0xDD86; // IPv6 in big endian
    
    struct ipv6_header* ip6hdr = (struct ipv6_header*)(rx_frame + IPV6_HEADER_LOC);
    ip6hdr->next_header = UDP_PROTOCOL;
    
    struct udp_header* udphdr = (struct udp_header*)(rx_frame + UDP_HEADER_LOC);
    udphdr->dst_port = 49999; // Below minimum valid port
    
    memcpy(eth_service.RxFrame, rx_frame, sizeof(rx_frame));
    
    u8* rcvbuf = NULL;
    u32 size = 0;
    
    Xil_Htons_ExpectAndReturn(udphdr->dst_port, 49999);

    // Act
    u32 result = parse_Rxpacket(&eth_service, rcvbuf, &size);
    
    // Assert
    TEST_ASSERT_EQUAL(ETH_FRAME_PORT_ERR, result);
    TEST_ASSERT_EQUAL(udphdr->dst_port, 49999);
}

void test_parse_Rxpacket_Should_Return_ETH_FRAME_AOS_ERR_When_App_Header_Wrong(void)
{
    // Arrange
    Eth_Service eth_service = {0};
    u8 rx_frame[1500] = {0};
    
    struct eth_header* ethhdr = (struct eth_header*)rx_frame;
    ethhdr->ether_type = 0xDD86; // IPv6 in big endian
    
    struct ipv6_header* ip6hdr = (struct ipv6_header*)(rx_frame + IPV6_HEADER_LOC);
    ip6hdr->next_header = UDP_PROTOCOL;
    
    struct udp_header* udphdr = (struct udp_header*)(rx_frame + UDP_HEADER_LOC);
    udphdr->dst_port = 50001; // Valid port
    
    struct app_header* apphdr = (struct app_header*)(rx_frame + APP_HEADER_LOC);
    apphdr->data_type = 0x02; // Wrong type
    apphdr->port = 0x29;      // Correct port
    
    memcpy(eth_service.RxFrame, rx_frame, sizeof(rx_frame));
    
    u8* rcvbuf = NULL;
    u32 size = 0;
    
    Xil_Htons_ExpectAndReturn(udphdr->dst_port, 50001);

    // Act
    u32 result = parse_Rxpacket(&eth_service, rcvbuf, &size);
    
    // Assert
    TEST_ASSERT_EQUAL(ETH_FRAME_AOS_ERR, result);
}

void test_parse_Rxpacket_Should_Return_ETH_FRAME_UDP_When_Valid_UDP_Packet(void)
{
    // Arrange
    Eth_Service eth_service = {0};
    u8 rx_frame[1500] = {0};
    
    struct eth_header* ethhdr = (struct eth_header*)rx_frame;
    ethhdr->ether_type = 0xDD86; // IPv6 in big endian
    
    struct ipv6_header* ip6hdr = (struct ipv6_header*)(rx_frame + IPV6_HEADER_LOC);
    ip6hdr->next_header = UDP_PROTOCOL;
    
    struct udp_header* udphdr = (struct udp_header*)(rx_frame + UDP_HEADER_LOC);
    udphdr->dst_port = 50001; // Valid port (in network byte order)
    
    struct app_header* apphdr = (struct app_header*)(rx_frame + APP_HEADER_LOC);
    apphdr->data_type = 0x01; // Correct type
    apphdr->port = 0x29;      // Correct port
    
    struct app_vcdu_prog* vcduprog = (struct app_vcdu_prog*)(rx_frame + APP_VCDU_DATA_LOC);
    // Fill with some test bitstream data
    
    memcpy(eth_service.RxFrame, rx_frame, sizeof(rx_frame));
    
    
    u8* rcvbuf = NULL;
    u32 size = 0;
    
    Xil_Htons_ExpectAndReturn(udphdr->dst_port, 50001);
    // Act
    u32 result = parse_Rxpacket(&eth_service, rcvbuf, &size);
    
    // Assert
    TEST_ASSERT_EQUAL(ETH_FRAME_UDP, result);
    TEST_ASSERT_EQUAL(sizeof(vcduprog->bit_stream_data), size);
    // Note: rcvbuf will point inside the rx_frame, but we can't easily test that without exposing internals
}